#include "LogStream.h"
#include <algorithm>
#include <assert.h>
#include <limits>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

namespace droneswarm
{
    const char digits[] = "9876543210123456789";
    const char *zero = digits + 9;

    // From muduo
    template < typename T >
    size_t convert( char buf[], T value )
    {
        T i = value;
        char *p = buf;

        do
        {
            int lsd = static_cast< int >( i % 10 );
            i /= 10;
            *p++ = zero[ lsd ];
        } while ( i != 0 );

        if ( value < 0 )
        {
            *p++ = '-';
        }
        *p = '\0';
        std::reverse( buf, p );

        return p - buf;
    }

    template class FixedBuffer< kSmallBuffer >;
    template class FixedBuffer< kLargeBuffer >;

    template < typename T >
    void LogStream::formatInteger( T v )
    {
        // buffer容不下kMaxNumericSize个字符的话会被直接丢弃
        if ( buffer_.avail() >= kMaxNumericSize )
        {
            size_t len = convert( buffer_.current(), v );
            buffer_.add( len );
        }
    }
    LogStream::LogStream() {}
    LogStream::~LogStream() {}
    LogStream &LogStream::operator<<( short v )
    {
        *this << static_cast< int >( v );
        return *this;
    }

    LogStream &LogStream::operator<<( unsigned short v )
    {
        *this << static_cast< unsigned int >( v );
        return *this;
    }

    LogStream &LogStream::operator<<( int v )
    {
        formatInteger( v );
        return *this;
    }

    LogStream &LogStream::operator<<( unsigned int v )
    {
        formatInteger( v );
        return *this;
    }

    LogStream &LogStream::operator<<( long v )
    {
        formatInteger( v );
        return *this;
    }

    LogStream &LogStream::operator<<( unsigned long v )
    {
        formatInteger( v );
        return *this;
    }

    LogStream &LogStream::operator<<( long long v )
    {
        formatInteger( v );
        return *this;
    }
    LogStream &LogStream::operator<<( const void *ptr )
    {
        std::ostringstream stream;
        stream << "Pointer address: " << ptr;
        std::string tmp = stream.str();
        int tmp_length = tmp.size();
        const char *c_tmp = tmp.c_str();
        append( c_tmp, tmp_length );
        return *this;
    }
    LogStream &LogStream::operator<<( unsigned long long v )
    {
        formatInteger( v );
        return *this;
    }

    LogStream &LogStream::operator<<( double v )
    {
        if ( buffer_.avail() >= kMaxNumericSize )
        {
            int len = snprintf( buffer_.current(), kMaxNumericSize, "%.12g", v );
            buffer_.add( len );
        }
        return *this;
    }

    LogStream &LogStream::operator<<( long double v )
    {
        if ( buffer_.avail() >= kMaxNumericSize )
        {
            int len = snprintf( buffer_.current(), kMaxNumericSize, "%.12Lg", v );
            buffer_.add( len );
        }
        return *this;
    }
}  // namespace droneswarm
